#include "libkysysinfo.h"
#include <dbus-1.0/dbus/dbus.h>
#include <kysdk/kysdk-base/cstring-extension.h>
#include <kysdk/kysdk-base/libkylog.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <X11/extensions/Xrandr.h>
#include <dirent.h>
#include <cjson/cJSON.h>


#define KYLIN_ACTIVATION_DBUS_ADDRESS   "org.freedesktop.activation"

#define SYSTEM_VERSION_PATH "/etc/kylin-version/kylin-system-version.conf" 
#define UPDATE_VERSION_PATH "/usr/share/kylin-update-desktop-config/data/" 
#define UPDATE_VERSION_PATH_REPLACE "/usr/share/kylin-update-desktop-config/config/"
#define VERSION_FILE_PATH   "/etc/kylin-version/kylin-system-version.conf"
#define OS_RELEASE_PATH     "/etc/os-release"
#define KYLIN_RELEASE_ID    "KYLIN_RELEASE_ID"
#define MAX_LINE 1024

#define BUF_SIZE 1024


static char* get_val_from_file(FILE *fp, const char *key)
{
    if (! fp)
        return NULL;
    char *val = NULL;
    char buf[1024] = {0};
    while (fgets(buf, 1024, fp))
    {
        if (strncmp(buf, key, strlen(key)) == 0)
        {
            val = strdup((char*)buf + strlen(key) +1);
            break;
        }
    }

    return val;
}

char* kdk_system_get_architecture()
{
    char *architecture = NULL;
#ifdef __linux__
    FILE *fp = fopen("/proc/osinfo", "r");
    if (!fp)
        return NULL;
    
    architecture = get_val_from_file(fp, "Architecture");
    if (!architecture)
        return NULL;
    strstrip(architecture, '\n');
    strstrip(architecture, '\t');

    fclose(fp);
#endif
    return architecture;
}

char* kdk_system_get_systemName()
{
    char *sysname = NULL;
#ifdef __linux__
    FILE *fp = fopen("/etc/os-release", "r");
    if (! fp)
        return NULL;
    
    sysname = get_val_from_file(fp, "NAME");
    if (!sysname)
        return NULL;
    strstrip(sysname, '\n');
    strstrip(sysname, '\"');

    fclose(fp);
#endif
    return sysname;
}

char* kdk_system_get_version(bool verbose)
{
    char *sysversion = NULL;
    if (verbose)
    {
#ifdef __linux__
        FILE *fp = fopen("/etc/.kyinfo", "r");
        if (!fp)
            return NULL;
        
        sysversion = get_val_from_file(fp, "milestone");
        if (!sysversion)
        {
            fclose(fp);
            return NULL;
        }
        fclose(fp);
    }
    else
    {
        FILE *fp = fopen("/etc/os-release", "r");
        if (!fp)
            return NULL;
        
        sysversion = get_val_from_file(fp, "VERSION");
        if (!sysversion)
        {
            fclose(fp);
            return NULL;
        }
        strstrip(sysversion, '\"');
        fclose(fp);
    }
    strstrip(sysversion, '\n');
    strstrip(sysversion, '\"');
#endif
    return sysversion;
}

int kdk_system_get_activationStatus(int *status_error_num,int *date_error_num)
{
    if (NULL == status_error_num || NULL == date_error_num)
    {
        klog_err("激活状态接口调用失败：参数错误\n");
        return -1;
    }
    
    int res = 0;

// #define _KYLIN_ACTIVATION_H_
#ifdef  __linux__
#ifdef _KYLIN_ACTIVATION_H_
    int err;
    int ret = -1;

    typedef int (*kylin_activation_activate_status)(int *);
    typedef int (*kylin_activation_trial_status)(int *);
    void *hwnd = dlopen("/usr/lib/libkylin-activation.so", RTLD_LAZY);

    if (!hwnd)
    {
        klog_err("加载libkylin-activation.so失败\n");
        return ret;
    }

    do
    {
        kylin_activation_activate_status pkylin_activation_activate_status = (kylin_activation_activate_status)dlsym(hwnd, "kylin_activation_activate_status");
        kylin_activation_trial_status pkylin_activation_trial_status = (kylin_activation_trial_status)dlsym(hwnd, "kylin_activation_trial_status");

        if (!pkylin_activation_activate_status || !pkylin_activation_trial_status)
        {
            klog_err("获取接口地址失败\n");
            break;
        }
        res = pkylin_activation_activate_status(&err);
        if (err != 0)
        {
            klog_err("激活状态获取失败：%d\n", err);
            ret = 0;
            break;
        }
        if (res)
        {
            ret = 1;
            break;
        }

        res = pkylin_activation_trial_status(&err);
        if (err != 0)
        {
            klog_err("试用状态获取失败：%d\n", err);
            ret = 0;
            break;
        }

        if (res == 1)
        {
            ret = 0;
            break;
        }
    } while (false);

    dlclose(hwnd);
    return ret;
#else // 修改dbus通信
    DBusConnection *conn;
    DBusError err;
    int ret;

    dbus_error_init(&err);
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);

    if (dbus_error_is_set(&err)) {
        fprintf(stderr, "Connection Error (%s)\n", err.message);
        dbus_error_free(&err);
    }

    if (NULL == conn) {
    return -1;
    }

    DBusMessage* status_msg=NULL;
    DBusMessage* status_pending_msg=NULL;
    DBusMessage* date_msg=NULL;
    DBusMessage* date_pending_msg=NULL;
    DBusMessageIter args;
    DBusPendingCall* status_pending=NULL;
    DBusPendingCall* date_pending=NULL;
    int stat;

    //获取激活状态
    status_msg = dbus_message_new_method_call("org.freedesktop.activation", // target for the method call
                                   "/org/freedesktop/activation", // object to call on
                                   "org.freedesktop.activation.interface", // interface to call on
                                   "status"); // method name

    if (!status_msg)
    { // -1 is default timeout
        klog_err("status_msg：dbus_message_new_method_call调用失败\n");
        return -1;
    }

    if (!dbus_connection_send_with_reply (conn, status_msg, &status_pending, -1)) { // -1 is default timeout
        klog_err("status_msg：dbus_connection_send_with_reply调用失败\n");
        return -1;
    }
    if (NULL == status_pending){
        klog_err("status_pending：返回值为null\n");
        return -1;  
    }
    dbus_connection_flush(conn);
    dbus_message_unref(status_msg);

    //接收返回值
    dbus_pending_call_block(status_pending); 
    status_pending_msg = dbus_pending_call_steal_reply(status_pending);
    if (NULL == status_pending_msg) {
        klog_err("status_pending_msg：获取激活状态接口返回值异常\n");
        return -1;
    }

    //释放status_pending
    dbus_pending_call_unref(status_pending);

    if (!dbus_message_iter_init(status_pending_msg, &args)){
        klog_err("status_pending_msg：dbus_message_iter_init获取激活状态接口返回值异常\n");
        return -1;
    }
    else
        dbus_message_iter_get_basic(&args, &stat);
    if (!dbus_message_iter_next(&args)){
        klog_err("status_pending_msg：dbus_message_iter_next获取激活状态接口返回值异常\n");
        return -1;
    }
    else
        dbus_message_iter_get_basic(&args, status_error_num);
    klog_debug("激活状态：%d，错误码：%d\n",stat,*status_error_num);

    //释放status_pending_msg
    dbus_message_unref(status_pending_msg);

    if (stat == 0)
    {
        char *date_stat;
        
        //获取技术服务日期
        date_msg = dbus_message_new_method_call("org.freedesktop.activation", // target for the method call
                            "/org/freedesktop/activation", // object to call on
                            "org.freedesktop.activation.interface", // interface to call on
                            "date"); // method name
        if (!dbus_connection_send_with_reply (conn, date_msg, &date_pending, -1)) { // -1 is default timeout
            klog_err("date_msg：dbus_connection_send_with_reply 接口调用失败\n");
            return -1;
        }
        if (NULL == date_pending){
            klog_err("date_pending：返回值为null\n");
            return -1;
        }
        dbus_connection_flush(conn);
        dbus_message_unref(date_msg);
        //接收返回值
        dbus_pending_call_block(date_pending); 
        date_pending_msg = dbus_pending_call_steal_reply(date_pending);

        if (NULL == date_pending_msg) {
            klog_err("date_pending_msg：Reply Null\n"); 
            return -1;
        }
        if (!dbus_message_iter_init(date_pending_msg, &args)){
            dbus_message_unref(date_pending_msg);
            klog_err("date_pending_msg：dbus_message_iter_init获取技术服务日期接口返回值异常\n");
            return -1;
        }
        else
            dbus_message_iter_get_basic(&args, &date_stat);
        if (!dbus_message_iter_next(&args)){
            dbus_message_unref(date_pending_msg);
            klog_err("date_pending_msg：dbus_message_iter_next获取技术服务日期接口返回值异常\n");
            return -1;
        }
        else
            dbus_message_iter_get_basic(&args, date_error_num);
        klog_debug("技术服务日期：%s，错误码：%d\n",date_stat,*date_error_num);
        if (*date_error_num == 0)
        {
            if (strcmp(date_stat, ""))
            {
                dbus_message_unref(date_pending_msg);
                return 2;
            }
            else
            {
                dbus_message_unref(date_pending_msg);
                return 0;
            }  
        }
        else{
            return 0;
        }
    }
    else if(stat == 1)
    {
        return 1;
    }
    
// #endif  // _KYLIN_ACTIVATION_H_
// #endif  // __linux__
    if (status_msg)
    {
        dbus_message_unref(status_msg);
    }
    if (status_pending_msg)
    {
        dbus_message_unref(status_pending_msg);
    }
    if (date_msg)
    {
        dbus_message_unref(date_msg);
    }
    if (date_pending_msg)
    {
        dbus_message_unref(date_pending_msg);
    }
    if (status_pending)
    {
        dbus_pending_call_unref(status_pending);
    }
    if (date_pending)
    {
        dbus_pending_call_unref(date_pending);
    }
    return 0;
#endif  // _KYLIN_ACTIVATION_H_
#endif  // __linux__
}

char* kdk_system_get_serialNumber()
{
    char *serial = NULL;
#ifdef  __linux__
#ifndef _KYLIN_ACTIVATION_H_ //修改成dbus通信
    FILE *fp = fopen("/etc/.kyinfo", "r");
    if (!fp)
        return NULL;
    
    serial = get_val_from_file(fp, "key");
    fclose(fp);
    if (serial)
        strskipspace(serial);
#else
    int err;

    typedef char *(*kylin_activation_get_serial_number)(int *);
    void *hwnd = dlopen("/usr/lib/libkylin-activation.so", RTLD_LAZY);

    if (!hwnd)
    {
        klog_err("加载libkylin-activation.so失败\n");
        return serial;
    }
    kylin_activation_get_serial_number pkylin_activation_get_serial_number = (kylin_activation_get_serial_number)dlsym(hwnd,"kylin_activation_get_serial_number");
    if(!pkylin_activation_get_serial_number)
    {
        klog_err("加载接口kylin_activation_get_serial_number失败\n");
        return serial;
    }
    serial = pkylin_activation_get_serial_number(&err);
    if (!serial)
    {
        klog_err("序列号获取失败：%d\n", err);
    }
    else
    {
        strskipspace(serial);
    }
    dlclose(hwnd);
    return serial;
#endif  // _KYLIN_ACTIVATION_H_
#endif  // __linux__
    return serial;
}

char* kdk_system_get_kernelVersion()
{
    char *kernver = NULL;
#ifdef __linux__
    FILE *fp = fopen("/proc/version", "r");
    if (!fp)
        return NULL;
    
    char buf[1024];
    if (fgets(buf, 1024, fp) == NULL)
    {
        fclose(fp);
        return NULL;
    }
    fclose(fp);

    char *p = buf;
    size_t pos = strfirstof(p, ' ');
    p += pos +1;
    pos = strfirstof(p, ' ');
    p += pos +1;
    size_t endpos = strfirstof(p, ' ');
    kernver = strndup(p, endpos);
#endif

    return kernver;
}

char* kdk_system_get_eUser()
{
    char *loginName = NULL;
#ifdef __linux__
    loginName = strdup(getpwuid(getuid())->pw_name);
#endif
    return loginName;
}

char* kdk_system_get_projectName()
{
    char *project_codename = NULL;
#ifdef __linux__
    FILE *fp = fopen("/etc/lsb-release", "rt");
    if (fp)
    {
        project_codename = get_val_from_file(fp, "PROJECT_CODENAME");
        fclose(fp);
    }

    if (!project_codename)
    {
        fp = fopen("/etc/os-release", "rt");
        ASSERT_NOT_NULL(fp, NULL);
        project_codename = get_val_from_file(fp, "PROJECT_CODENAME");
        fclose(fp);
    }
    if (project_codename)
        strstripspace(project_codename);
#endif
    return project_codename;
}

char* kdk_system_get_projectSubName()
{
    char *project_subcodename = NULL;
#ifdef __linux__
    FILE *fp = fopen("/etc/lsb-release", "rt");
    if (fp)
    {
        project_subcodename = get_val_from_file(fp, "SUB_PROJECT_CODENAME");
        fclose(fp);
    }

    if (!project_subcodename)
    {
        fp = fopen("/etc/os-release", "rt");
        ASSERT_NOT_NULL(fp, NULL);
        project_subcodename = get_val_from_file(fp, "SUB_PROJECT_CODENAME");
        fclose(fp);
    }
    if (project_subcodename)
        strstripspace(project_subcodename);
#endif
    return project_subcodename;
}

unsigned int kdk_system_get_productFeatures()
{
    char *product_features = NULL;
    unsigned int res = 0;
#ifdef  __linux__
    FILE *fp = fopen("/etc/lsb-release", "rt");
    if (fp)
    {
        product_features = get_val_from_file(fp, "PRODUCT_FEATURES");
        fclose(fp);
    }

    if (!product_features)
    {
        fp = fopen("/etc/os-release", "rt");
        ASSERT_NOT_NULL(fp, 0);
        product_features = get_val_from_file(fp, "PRODUCT_FEATURES");
        fclose(fp);
    }
    if (product_features)
    {
        strstripspace(product_features);
        res = atoi(product_features);
    }
#endif

    return res;
}

char* kdk_system_get_hostVirtType()
{
    char *virtType = (char*)malloc(sizeof(char) * 65);
    ASSERT_NOT_NULL(virtType, NULL);
#ifdef __linux__
    FILE *pipeLine = popen("systemd-detect-virt", "r");  // 建立流管道
    if (!pipeLine)
    {
        free(virtType);
        return NULL;
    }
    if (fgets(virtType, 64 * sizeof(char), pipeLine) == NULL)
    {
		SAFE_FREE(virtType);
        pclose(pipeLine);
        return NULL;
	}
    pclose(pipeLine);
    strstripspace(virtType);
    if (strcmp(virtType, "microsoft") == 0)
        strcpy(virtType, "hyper-v");
    else if (strcmp(virtType, "oracle") == 0)
        strcpy(virtType, "orcale virtualbox");
#endif
    return virtType;
}

char* kdk_system_get_hostCloudPlatform()
{
    char *cloudplat = (char *)malloc(sizeof(char) * 65);
    ASSERT_NOT_NULL(cloudplat, NULL);
#ifdef __linux__
    cloudplat[0] = 0;
    char buf[256] = {0};
    bool res_flag = false;
    if (geteuid() == 0) // root 用户，可以用dmidecode
    {
        FILE *pipeLine = popen("dmidecode -s chassis-manufacturer", "r");
        if (__glibc_likely(pipeLine != NULL))
        {
            fgets(buf, 255 * sizeof(char), pipeLine);
            strstripspace(buf);
            if (strcmp(buf, "Huawei Inc.") == 0)        // 华为云
            {
                strcpy(cloudplat, "huawei");
                res_flag = true;
            }
            pclose(pipeLine);
        }
        if (!res_flag)
        {
            pipeLine = popen("dmidecode -s chassis-asset-tag", "r");
            if (__glibc_likely(pipeLine != NULL))
            {
                fgets(buf, 255 * sizeof(char), pipeLine);
                strstripspace(buf);
                if (strcmp(buf, "HUAWEICLOUD") == 0)    // 华为云
                {
                    strcpy(cloudplat, "huawei");
                }
                pclose(pipeLine);
            }
        }
    }
    else        // 普通用户，只能读取文件
    {
        FILE *fp = fopen("/sys/devices/virtual/dmi/id/chassis_vendor", "rt");
        if (__glibc_likely(fp != NULL))
        {
            fgets(buf, 255 * sizeof(char), fp);
            strstripspace(buf);
            if (strcmp(buf, "Huawei Inc.") == 0)        // 华为云
            {
                strcpy(cloudplat, "huawei");
                res_flag = true;
            }
            fclose(fp);
        }
        if (!res_flag)
        {
            fp = fopen("chassis_asset_tag", "r");
            if (__glibc_likely(fp != NULL))
            {
                fgets(buf, 255 * sizeof(char), fp);
                strstripspace(buf);
                if (strcmp(buf, "HUAWEICLOUD") == 0)    // 华为云
                {
                    strcpy(cloudplat, "huawei");
                }
                fclose(fp);
            }
        }
    }

    if (strlen(cloudplat) == 0)
        strcpy(cloudplat, "none");
#endif
    return cloudplat;
}

bool kdk_system_is_zyj(void)
{
    bool bool_value = false;
    char *project_codename = kdk_system_get_projectName();
    
    if (project_codename && (strstr(project_codename, "zyj") || strstr(project_codename, "ZYJ")))
        bool_value = TRUE;
        
    SAFE_FREE(project_codename);
    return bool_value;
}

char *readReleaseFile()
{
    char buf[MAX_LINE];  
    FILE *fp; int len;  
    static char * os_version = NULL;
      
    if((fp = fopen(OS_RELEASE_PATH, "r")) == NULL) {
        printf("fail to read.\n");
        return os_version;
    }

    while(fgets(buf,MAX_LINE,fp) != NULL) {
        len = strlen(buf);
        buf[len-1] = '\0';
        if ((strstr (buf, KYLIN_RELEASE_ID) != NULL )) {
            os_version = strdup (buf);
            printf("Get os version     ---  %s \n",os_version);
        }
    }
    return os_version;
}

char *parseJsonText(char *text)
{
    char *out;
	cJSON *json;
	cJSON *childJson = NULL;
    char * version;
    
    // printf("%s \n",text);

    //获取补丁版本
	json=cJSON_Parse(text);
	if (!json) {
        printf("Error before: [%s]\n",cJSON_GetErrorPtr());
        version=NULL;
    } else {
		childJson = cJSON_GetObjectItem(json, "version");
		if (!childJson) {
            printf("Error before: [%s]\n",cJSON_GetErrorPtr());
            version=NULL;
        } else {
			printf("Get update version ---  %s \r\n",childJson->valuestring);
            version=strdup(childJson->valuestring);
		}

		out=cJSON_Print(json);
		cJSON_Delete(childJson);
		free(out);
    }
    return version;
}

char *readJsonFile(char *json_file)
{
    FILE *fp; long len;
    char *data;
    static char *update_version;

    fp=fopen(json_file,"rb");fseek(fp,0,SEEK_END);len=ftell(fp);fseek(fp,0,SEEK_SET);
    printf("File [ %s ] size: %ld. \n", json_file, len);
	data=(char*)malloc(len+1);fread(data,1,len,fp);fclose(fp);
	update_version = parseJsonText(data);
	free(data);
    return update_version;
}

void getDefaultVersion( version_t *ver )
{
    char *update_version, *os_version;
    os_version     = readReleaseFile(); //os-version
    asprintf (&ver->os_version, "%s", os_version);
    printf("Get os_version: %s\n",ver->os_version);
    if ( (access (UPDATE_VERSION_PATH_REPLACE "kylin-update-desktop-system.json", F_OK) == 0) ||\
         (access (UPDATE_VERSION_PATH "kylin-update-desktop-system.json", F_OK) == 0) ){
        if ( access (UPDATE_VERSION_PATH_REPLACE "kylin-update-desktop-system.json", F_OK) == 0) {
            update_version = readJsonFile(UPDATE_VERSION_PATH_REPLACE "kylin-update-desktop-system.json");  //config update version
        } else if ( access (UPDATE_VERSION_PATH "kylin-update-desktop-system.json", F_OK) == 0) {
            update_version = readJsonFile(UPDATE_VERSION_PATH "kylin-update-desktop-system.json");  //data update version
        }
        asprintf (&ver->update_version, "%s", update_version);
        printf("Get update_version: %s\n",ver->update_version);
    } else {
        printf("update version file(config|data) doesn't exist..\n");
    }
}

/** 函数名：      GetIniKeyString 
*** 入口参数：    section :配置文件中一组数据的标识 
***              key :这组数据中要读出的值的标识 
***             filename :要读取的文件路径 
*** 返回值：      找到需要查的值则返回正确结果 0 
***              否则返回-1     */  
int GetIniKeyString(char *section,char *key,char *filename,char *buf)
{  
    FILE *fp;  
    int  flag = 0;  
    char sTitle[64], *wTmp;
    char sLine[1024];        
    sprintf(sTitle, "[%s]", section);
                     
    if(NULL == (fp = fopen(filename, "r"))) {  
        perror("fopen");  
        return -1;
    }
    while (NULL != fgets(sLine, 1024, fp)) {  
        // 这是注释行  
        if (0 == strncmp("//", sLine, 2)) continue;  
        if ('#' == sLine[0])              continue;        
        wTmp = strchr(sLine, '=');  
        if ((NULL != wTmp) && (1 == flag)) {  
            if (0 == strncmp(key, sLine, strlen(key))) { // 长度依文件读取的为准  
                sLine[strlen(sLine) - 1] = '\0';  
                fclose(fp);
                while(*(wTmp + 1) == ' '){
                    wTmp++;
                }
                strcpy(buf,wTmp + 1);
                return 0;  
            }  
        } else {  
            if (0 == strncmp(sTitle, sLine, strlen(sTitle))) { // 长度依文件读取的为准  
                flag = 1; // 找到标题位置  
            }  
        }  
    }  
    fclose(fp);  
    return -1;  
}        
      
/** 函数名:         PutIniKeyString 
*** 入口参数:        section:配置文件中一组数据的标识 
***                key:这组数据中要读出的值的标识 
***                val:更改后的值 
***                filename:要读取的文件路径 
*** 返回值:         成功返回  0 
***                否则返回 -1      */  
int PutIniKeyString(char *section,char *key,char *val,char *filename)
{  
    FILE *fpr, *fpw;  
    int  flag = 0;  
    char sLine[1024], sTitle[32], *wTmp;        
    sprintf(sTitle, "[%s]", section);  
    if (NULL == (fpr = fopen(filename, "r")))  
        return -1;// 读取原文件  
    sprintf(sLine, "%s.tmp", filename);  
    if (NULL == (fpw = fopen(sLine,    "w")))  
        return -1;// 写入临时文件        
    while (NULL != fgets(sLine, 1024, fpr)) {  
        if (2 != flag) { // 如果找到要修改的那一行，则不会执行内部的操作  
            wTmp = strchr(sLine, '=');  
            if ((NULL != wTmp) && (1 == flag)) {  
                if (0 == strncmp(key, sLine, strlen(key))) { // 长度依文件读取的为准 
                    flag = 2;// 更改值，方便写入文件  
                    sprintf(wTmp + 1, " %s\n", val);
                }  
            } else {
                if (0 == strncmp(sTitle, sLine, strlen(sTitle))) { // 长度依文件读取的为准
                    flag = 1; // 找到标题位置  
                }  
            }  
        }        
        fputs(sLine, fpw); // 写入临时文件 
    }  
    fclose(fpr);  
    fclose(fpw);        
    sprintf(sLine, "%s.tmp", filename);  
    return rename(sLine, filename);// 将临时文件更新到原文件  
}

void getCurrentVersion(version_t *ver)
{
    char buff[100];

    if ( 0 == GetIniKeyString("SYSTEM", "os_version", VERSION_FILE_PATH, buff)) {
        if (ver->os_version == NULL)
            asprintf (&ver->os_version, "%s", buff);
        printf("Get os_version: %s\n",ver->os_version);
    }

    if (0 == GetIniKeyString("SYSTEM", "update_version", VERSION_FILE_PATH, buff)) 
    {
        if (ver->update_version == NULL)
            asprintf (&ver->update_version, "%s", buff);
        printf("Get update_version: %s\n",ver->update_version);
    }
}

version_t kdk_system_get_version_detaile()
{ 
    version_t version = { 0 };

    if ( access (SYSTEM_VERSION_PATH, F_OK) == 0) {
        printf("System version file is exist..\n");
        //get current version 
        getCurrentVersion(&version);
    } else { 
        printf("System version file doesn't exist..\n");
        //get default version 
        getDefaultVersion(&version);
    } 

    if (((version.os_version == NULL) || (strstr (version.os_version, "null") != NULL )) && version.update_version != NULL) {
        asprintf (&version.os_version, "%s", version.update_version);
    } else if (( (version.update_version == NULL) || (strstr (version.update_version, "null") != NULL )) && version.os_version != NULL) {
        asprintf (&version.update_version, "%s", version.os_version);
    } else if ( ((version.os_version == NULL) || (strstr (version.os_version, "null") != NULL )) && ( (version.update_version == NULL) || (strstr (version.update_version, "null") != NULL )) ) {
        asprintf (&version.os_version, "%s", "");
        asprintf (&version.update_version, "%s", "");
    }

    printf("os_version :%d\n", strlen(version.os_version));
    printf("update_version :%d\n", strlen(version.update_version));

    return version;
}

char** kdk_system_get_resolving_power()
{
    Display *disp;
    XRRScreenResources *screen;
    XRROutputInfo *info;
    XRRCrtcInfo *crtc_info;
    int iscres;
    int icrtc;
    char *name = (char *)malloc(sizeof(char) * 256);
    char *tmp = (char *)malloc(256*sizeof(char));
    char **res = NULL;
    int count = 0;
     char path[50] = {0};
    DIR *dirfd = NULL;
    struct dirent *direproc, *direfd;
    FILE *fp;
    char buf[BUF_SIZE];
    char *buff[5], *p = NULL;
    int i = 0;
    char *ret = (char *)malloc(200* sizeof(char));
    char *mode = (char *)malloc(200* sizeof(char));
    char * temp = (char *)malloc(20* sizeof(char));

    disp = XOpenDisplay(0);
    screen = XRRGetScreenResources (disp, DefaultRootWindow(disp));
    for (iscres = screen->noutput; iscres > 0; ) {
        --iscres;

        info = XRRGetOutputInfo (disp, screen, screen->outputs[iscres]);
        if (info->connection == RR_Connected) {
            for (icrtc = info->ncrtc; icrtc > 0;) {
                memset(tmp,0,256*sizeof(char));
                strcpy(name, info->name);
                strcat(tmp,name);
                strcat(tmp,", ");
                --icrtc;

                crtc_info = XRRGetCrtcInfo (disp, screen, screen->crtcs[icrtc]);
                // fprintf(stderr, "==> %dx%d+%dx%d\n", crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height);
                sprintf(name, "%dx%d", crtc_info->width, crtc_info->height);
                strcat(tmp,name);
                strcat(tmp,", ");

                dirfd = opendir("/sys/class/drm");
                if (! dirfd) {
                    return NULL;
                }
                while ((direfd = readdir(dirfd))) {
                    strcpy(temp, info->name);
                    p = strtok(temp, "-");
                    while(p)
                    {
                        buff[i] = p;
                        i++;
                        p = strtok(NULL,"-");
                    }
                    if(strstr(direfd->d_name, buff[0]))
                    {
                        sprintf(path, "/sys/class/drm/%s/modes", direfd->d_name);
                        fp = fopen(path, "r");
                        if(fp == NULL)
                        {
                            return NULL;
                        }
                        memset(mode,0,200*sizeof(char));
                        while(fgets(buf, BUF_SIZE-1, fp)){
                            buf[strlen(buf) - 1] = '\0';
                            if(!strstr(mode, buf))
                            {
                                memset(ret,0,200*sizeof(char));
                                strcpy(ret, buf);
                                strcat(mode,ret);
                                strcat(mode," ");
                                
                            }else{
                                continue;
                            }
                        }
                    }else{
                        memset(mode,0,200*sizeof(char));
                        memset(ret,0,200*sizeof(char));
                        strcpy(ret, name);
                        strcat(mode,ret);
                        strcat(mode," ");
                    }
                }
                strcat(tmp, mode);


                res = realloc(res, (count + 1) * sizeof(char *));

                res[count] = malloc(256 * sizeof(char) + 1);
                strcpy(res[count], tmp);
                count++;

                XRRFreeCrtcInfo(crtc_info);
            }
        }
        XRRFreeOutputInfo (info);
    }
    XRRFreeScreenResources(screen);
    free(name);
    free(tmp);
    free(temp);
    free(mode);
    free(ret);
    res[count] = NULL;
    return res;
}

inline void kdk_resolving_freeall(char **list)
{
    if (! list)
        return;
    size_t index = 0;
    while (list[index])
    {
        free(list[index]);
        index ++;
    }
    free(list);
}